 <!DOCTYPE html>
 <html lang="en">
 <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
 </head>
 <body>
    <div id="app">
        <div data-bind="list" data-on="charset" data-event="click"></div>
        <div data-bind="num" ></div>
        <!-- <div data-bind="list"><input type="text" ></div> -->
    </div>

    <!-- <div id="aaa">
        <ul id="bbb">
            <li>1</li>
            <li>2</li>
            <li>3</li>
        </ul>
    </div> -->
 <script>
    // let asd=document.querySelector("#aaa")
    // let uls=asd.querySelectorAll('*[id]')
    // console.log(uls);
    let as={
        a:0,
        a1:6,
        a2:1,
        a3:2,
        a4:01,
        a5:02,
    }
    // console.log(Object.entries(as));
    // for (const [index,value] of Object.entries(as)) {
    //     console.log(index,value);
    // }
    // function initReactiveData(originObj){
    //     Object.keys(originObj).forEach((property) => {
    //         // console.log(originObj[property],6666);
    //         // property是objec的key值
    //         // Object.keys(originObj)可以将key值存在数组中
    //         Object.defineProperty(this, property, {
    //         get() {
    //             //   console.log(property + "被读取");
    //             return originObj[property];
    //         },
    //         set(value) {
    //             if (originObj[property] !== value) {
    //             // console.log("修改obj的" + property + "属性为：" + value);
    //             originObj[property] = value;
    //             this.updateDom(property, value);
    //             }
    //         },
    //         });
    //         this.a=6
    //         console.log(this.a);
    //     });
    // }

    class Vue {
        constructor({
                el = "body", 
                data = () => ({}), 
                methods = {},
                beforeCreate = () => {},
                created = () => {},
                beforeMount = () => {},
                mounted = () => {},
                beforeUpdate = () => {},
                updated = () => {} 
            }) {
                this.$el = document.querySelector(el);
                this.$data = data();
                this.beforeUpdate = beforeUpdate.bind(this);
                this.updated = updated.bind(this);
                //挂在前，初始化数据和部分生命周期钩子
                beforeCreate.call(this);
                this.initReactiveData(this.$data);
                this.initMethods(methods);
                // 数据已经通过initReactive方法初始化成了响应式的数据，并且也将methods配置项的方法绑定到了实例this上
                created.call(this);
                // 开始挂载，初始化dom（vue模板语法是有编译的过程的，这儿我们不去做这个复杂的工作），调用beforeMount钩子
                // 然后渲染vue语法数据，绑定事件以及建立好数据的双向绑定
                beforeMount.call(this);
                this.initDom();
                this.bindEvent();
                this.createEventListener();
                // 挂载完成，调用mounted方法
                mounted.call(this);
        }
        initMethods(methods) {
            console.log(methods);
            Object.entries(methods).forEach(
            ([methodName, method]) => (this[methodName] = method.bind(this))
            );
        }

        updateDom(property, value) {
            console.log(property + "发生了变化，需要去更新dom", value);
            this.initDom(property);
            //   initDom.apply(this, [property, value]);
        }

        initDom(changedProperty) {
            const modelSelector = changedProperty
            ? `*[v-model=${changedProperty}]`
            : "*[v-model]";
            const dataOnSelector = changedProperty
            ? `*[data-bind=${changedProperty}]`
            : "*[data-bind]";
            const domModelList = this.$el.querySelectorAll(modelSelector);
            const domDataOnList = this.$el.querySelectorAll(dataOnSelector);
            domModelList.forEach((el) => {
            const property = el.getAttribute("v-model");
            const value = property.value;
            if (value !== this[property]) {
                el.value = this[property];
            }
            });

            domDataOnList.forEach((el) => {
            const property = el.getAttribute("data-bind");
            if (el.innerText !== this[property]) {
                // console.log(el.innerText);
                el.innerText = this[property];
            }
            });
        }

        initReactiveData(originObj = {}) {
            Object.keys(originObj).forEach((property) => {
            Object.defineProperty(this, property, {
                get() {
                //   console.log(property + "被读取");
                return originObj[property];
                },
                set(value) {
                    this.beforeUpdate.call(this);
                if (originObj[property] !== value) {
                    // console.log("修改obj的" + property + "属性为：" + value);
                    originObj[property] = value;
                    this.updateDom(property, value);
                }
                    this.updated.call(this);
                },
            });
            });
        }

        createEventListener() {
            const modelDomList = this.$el.querySelectorAll("*[v-model]");
            modelDomList.forEach((el) => {
            const property = el.getAttribute("v-model");
            el.addEventListener("input", ({ target }) => {
                this[property] = target.value;
            });
            });
        }

        bindEvent() {
            const doms = this.$el.querySelectorAll("*[data-on]");
            doms.forEach((el) => {
            const eventName = el.getAttribute("data-on");
            const eventType = el.getAttribute("data-event");
            switch (eventType) {
                case "click":
                console.log("in", this, eventName);
                el.addEventListener("click", this[eventName]);
            }
            });
        }
    }

    let vm=new Vue({
        el: "#app",
        data(){
            return{
                list:"666",
                num:"18"
            }
        },
        methods:{
            charset(e){
                console.log(5555)
            }
        },
        beforeCreate() {
          console.log("beforeCreate", this.num); // undefind, 因为这个时候data还没有被初始化为响应式数据
        },
        created() {
          console.log("created", this.num); // joey， 这时候data已经通过initReactive方法被处理成了响应式数据，并且绑定到vue实例身上
        },
        beforeMount() {
          console.log("beforeMounte", 666); // ""，这时候data初始化完成，但是还没挂载（赋值）到页面上
        },
        mounted() {
          console.log("mounted", 666); // 10， 这时候页面已经挂载（初始化完成）
        },
        beforeUpdate() {
          console.log("beforeUpdate", 666); //现在vue监听到了数据的变化，会调用beforeUpdate，但此时数据还没有变化，页面也没更新
        },
        updated() {
          console.log("updated", 666); // 11，数据更新，并且找到需要改变的dom元素且dom更新完成
        }
    })
    // console.log(vm.initMethods(as));
 </script>
 </body>
 </html>